this._defaultService = null;
this._preemptingService = null;
+ this._fingerprintReaderType = FingerprintReaderType.NONE;
this._messageQueue = [];
this._messageQueueTimeoutId = 0;
this._userName = userName;
this.reauthenticating = false;
- this._checkForFingerprintReader().catch(logError);
+ this._checkForFingerprintReader().catch(e =>
+ this._handleFingerprintError(e));
// If possible, reauthenticate an already running session,
// so any session specific credentials get updated appropriately
this.emit('show-message', null, null, MessageType.NONE);
}
- _initFingerprintManager() {
+ async _initFingerprintManager() {
if (this._fprintManager)
return;
- this._fprintManager = new Gio.DBusProxy({
+ const fprintManager = new Gio.DBusProxy({
g_connection: Gio.DBus.system,
g_name: 'net.reactivated.Fprint',
g_object_path: '/net/reactivated/Fprint/Manager',
g_interface_name: FprintManagerInfo.name,
g_interface_info: FprintManagerInfo,
- g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES,
+ g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES |
+ Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION |
+ Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
});
- this._fprintManager.init(null);
+
+ try {
+ if (!this._getDetectedDefaultService()) {
+ // Other authentication methods would have already been detected by
+ // now as possibilities if they were available.
+ // If we're here it means that FINGERPRINT_AUTHENTICATION_KEY is
+ // true and so fingerprint authentication is our last potential
+ // option, so go ahead a synchronously look for a fingerprint device
+ // during startup or default service update.
+ fprintManager.init(null);
+ const [devicePath] = fprintManager.GetDefaultDeviceSync();
+ this._fprintManager = fprintManager;
+
+ const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
+ 'net.reactivated.Fprint', devicePath, null, null,
+ Gio.DBusProxyFlags.NOT_CONNECT_SIGNALS);
+ this._setFingerprintReaderType(fprintDeviceProxy['scan-type']);
+ } else {
+ // Ensure fingerprint service starts, but do not wait for it
+ const cancellable = this._cancellable;
+ await fprintManager.init_async(GLib.PRIORITY_DEFAULT, cancellable);
+ await this._updateFingerprintReaderType(fprintManager, cancellable);
+ this._fprintManager = fprintManager;
+ }
+ } catch (e) {
+ this._handleFingerprintError(e);
+ }
}
- async _checkForFingerprintReader() {
+ _handleFingerprintError(e) {
this._fingerprintReaderType = FingerprintReaderType.NONE;
+ if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ return;
+ if (e.matches(Gio.DBusError, Gio.DBusError.SERVICE_UNKNOWN))
+ return;
+
+ if (Gio.DBusError.is_remote_error(e) &&
+ Gio.DBusError.get_remote_error(e) ===
+ 'net.reactivated.Fprint.Error.NoSuchDevice')
+ return;
+
+ logError(e, 'Failed to interact with fprintd service');
+ }
+
+ async _checkForFingerprintReader() {
if (!this._fprintManager) {
this._updateDefaultService();
return;
}
- const [devicePath] = await this._fprintManager.GetDefaultDeviceAsync(
- Gio.DBusCallFlags.NONE, this._cancellable);
+ if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
+ return;
+
+ await this._updateFingerprintReaderType(this._fprintManager, this._cancellable);
+ }
+
+ async _updateFingerprintReaderType(fprintManager, cancellable) {
+ // Wrappers don't support null cancellable, so let's ignore it in case
+ const args = cancellable ? [cancellable] : [];
+ const [devicePath] = await fprintManager.GetDefaultDeviceAsync(...args);
const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
'net.reactivated.Fprint',
devicePath);
- const fprintDeviceType = fprintDeviceProxy['scan-type'];
-
- this._fingerprintReaderType = fprintDeviceType === 'swipe'
- ? FingerprintReaderType.SWIPE
- : FingerprintReaderType.PRESS;
+ this._setFingerprintReaderType(fprintDeviceProxy['scan-type']);
this._updateDefaultService();
if (this._userVerifier &&
}
}
+ _setFingerprintReaderType(fprintDeviceType) {
+ this._fingerprintReaderType =
+ FingerprintReaderType[fprintDeviceType.toUpperCase()];
+
+ if (this._fingerprintReaderType === undefined)
+ throw new Error(`Unexpected fingerprint device type '${fprintDeviceType}'`);
+ }
+
_onCredentialManagerAuthenticated(credentialManager, _token) {
this._preemptingService = credentialManager.service;
this.emit('credential-manager-authenticated');
let needsReset = false;
if (this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) {
- this._initFingerprintManager();
+ this._initFingerprintManager().catch(logError);
} else if (this._fingerprintManager) {
this._fingerprintManager = null;
this._fingerprintReaderType = FingerprintReaderType.NONE;
this._cancelAndReset();
}
- _updateDefaultService() {
- const oldDefaultService = this._defaultService;
-
+ _getDetectedDefaultService() {
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
- this._defaultService = PASSWORD_SERVICE_NAME;
+ return PASSWORD_SERVICE_NAME;
else if (this._smartcardManager)
- this._defaultService = SMARTCARD_SERVICE_NAME;
+ return SMARTCARD_SERVICE_NAME;
else if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
- this._defaultService = FINGERPRINT_SERVICE_NAME;
+ return FINGERPRINT_SERVICE_NAME;
+ return null;
+ }
+
+ _updateDefaultService() {
+ const oldDefaultService = this._defaultService;
+ this._defaultService = this._getDetectedDefaultService();
if (!this._defaultService) {
log('no authentication service is enabled, using password authentication');